package cn.javaxc.mvcwork.modules.admin;
import cn.javaxc.mvcwork.controller.MVCConstant;
import cn.javaxc.mvcwork.framework.actions.TActionContext;
import cn.javaxc.mvcwork.framework.beans.TFormBean;
import cn.javaxc.mvcwork.framework.database.ConnectionElement;
import cn.javaxc.model.base.*;
import cn.javaxc.mvcwork.util.helper.FrameHelper;
import cn.javaxc.mvcwork.modules.admin.Contact;
import cn.javaxc.mvcwork.controller.MVCConfig;
import cn.javaxc.mvcwork.util.common.*;
import java.sql.*;
import java.text.DateFormat;
import java.util.*;
import org.apache.log4j.Logger;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonIgnore;



public class User extends TFormBean {

  private static final long serialVersionUID = -8407265772708150808L;

  private static final Logger log = Logger.getLogger(cn.javaxc.mvcwork.modules.admin.User.class);

  protected String errmsg = "";

  protected int id = -1;

  protected String username = null;

  protected String encryptedPassword = null;

  protected String password = null;

  protected String password1 = null;


  protected String webdavPassword = null;

  protected int contactId = -1;

  protected int roleId = -1;

  protected String role = null;

  private int roleType = -1;

  protected int managerId = -1;

  protected User managerUser = null;

  protected String ip = null;

  protected String timeZone = null;

  private String currency = null;

  private String language = null;

  private Locale locale = null;

  protected int startOfDay = -1;

  protected int endOfDay = -1;

  protected int enteredBy = -1;

  protected int modifiedBy = -1;

  protected boolean enabled = true;

  protected boolean hasWebdavAccess = false;

  protected boolean hasHttpApiAccess = false;

  private int siteId = -1;

  private String siteIdName = null;

  @JsonIgnore
  protected java.sql.Timestamp entered = null;
  @JsonIgnore  
  protected java.sql.Timestamp modified = null;
  @JsonIgnore
  protected java.sql.Timestamp lastLogin = null;
  @JsonIgnore
  protected java.sql.Timestamp expires = null;

  protected String previousUsername = null;

  private int assistant = -1;

  private int alias = -1;

  protected boolean hidden = false;

  // Related objects
  protected Contact contact = new Contact();


  // Lazy loading properties
  protected boolean buildContact = false;

  protected boolean buildContactDetails = false;

  protected boolean buildHierarchy = false;


  // check to see if manager user is enabled
  private boolean managerUserEnabled = true;













  private UserPermissionList userPermissionList=new UserPermissionList();
	
  
  public User() {
  }


  public User( int userId) throws Exception {
    buildRecord( userId);
  }


  
  public void setWebdavPassword(String tmp) {
    this.webdavPassword = tmp;
  }

  
  public String getWebdavPassword() {
    return webdavPassword;
  }


  
  public boolean getHasWebdavAccess() {
    return hasWebdavAccess;
  }

  
  public void setHasWebdavAccess(boolean tmp) {
    this.hasWebdavAccess = tmp;
  }

  
  public void setHasWebdavAccess(String tmp) {
    this.hasWebdavAccess = DatabaseUtils.parseBoolean(tmp);
  }

  
  public boolean getHasHttpApiAccess() {
    return hasHttpApiAccess;
  }

  
  public void setHasHttpApiAccess(boolean tmp) {
    this.hasHttpApiAccess = tmp;
  }

  
  public void setHasHttpApiAccess(String tmp) {
    this.hasHttpApiAccess = DatabaseUtils.parseBoolean(tmp);
  }


  public boolean getHidden() {
    return hidden;
  }

  
  public void setHidden(boolean tmp) {
    this.hidden = tmp;
  }

  
  public void setHidden(String tmp) {
    this.hidden = DatabaseUtils.parseBoolean(tmp);
  }

  




  
  public void setExpires(java.sql.Timestamp expires) {
    this.expires = expires;
    checkHidden();
  }

  
  public void setExpires(String tmp) {
    this.expires = DatabaseUtils.parseDateToTimestamp(tmp);
    checkHidden();
  }

  
  public String generateRandomPassword()  {
    String newPassword = String.valueOf(StringUtils.rand(100000, 999999));
    this.setPassword1(newPassword);
//    this.setPassword2(newPassword);
    this.newPassword();
    return newPassword;
  }

  
  public void setAssistant(int tmp) {
    this.assistant = tmp;
  }


  
  public void setAssistant(String tmp) {
    this.assistant = Integer.parseInt(tmp);
  }

  
  public void setAlias(int tmp) {
    alias = tmp;
  }

  
  public void setAlias(String tmp) {
    alias = Integer.parseInt(tmp);
  }


  
  public void setManagerUserEnabled(boolean managerUserEnabled) {
    this.managerUserEnabled = managerUserEnabled;
  }

  
  public boolean getManagerUserEnabled() {
    return managerUserEnabled;
  }



  
  public void setId(int tmp) {
    this.id = tmp;
  }

  
  public void setId(String tmp) {
    this.id = Integer.parseInt(tmp);
  }

  
  public void setUsername(String tmp) {
    this.username = tmp;
  }

  
  public void setPreviousUsername(String tmp) {
    this.previousUsername = tmp;
  }

  
  public void setEncryptedPassword(String tmp) {
    this.encryptedPassword = tmp;
  }

  
  public void setPassword(String tmp) {
    this.password = tmp;
  }

  
  public void setPassword1(String tmp) {
    this.password1 = tmp;
  }

  

  
  public void setEntered(java.sql.Timestamp tmp) {
    this.entered = tmp;
  }

  
  public void setModified(java.sql.Timestamp tmp) {
    this.modified = tmp;
  }

  
  public void setEntered(String tmp) {
    this.entered = DateUtils.parseTimestampString(tmp);
  }

  
  public void setModified(String tmp) {
    this.modified = DateUtils.parseTimestampString(tmp);
  }

  
  public void setContactId(int tmp) {
    this.contactId = tmp;
    this.contact.setId(tmp);
  }

  
  public void setContactId(String tmp) {
    if (tmp != null) {
      setContactId(Integer.parseInt(tmp));
    }
  }

  
  public void setRoleId(int tmp) {
    this.roleId = tmp;
  }

  
  
  public void setRoleId(String tmp) {
    if (tmp != null) {
      this.roleId = Integer.parseInt(tmp);
    }
  }

  
  public void setSiteId(int tmp) {
    siteId = tmp;
  }

  
  public void setSiteId(String tmp) {
    this.siteId = Integer.parseInt(tmp);
  }


  
  public void setRole(String tmp) {
    this.role = tmp;
  }

  
  public void setManagerId(int tmp) {
    this.managerId = (tmp);
  }

  
  public void setManagerId(String tmp) {
    if (tmp != null) {
      this.managerId = Integer.parseInt(tmp);
    }
  }

  
  public void setEnteredBy(int tmp) {
    this.enteredBy = tmp;
  }

  
  public void setEnteredBy(String tmp) {
    if (tmp != null) {
      this.enteredBy = Integer.parseInt(tmp);
    }
  }

  
  public void setModifiedBy(int tmp) {
    this.modifiedBy = tmp;
  }

  
  public void setModifiedBy(String tmp) {
    this.modifiedBy = Integer.parseInt(tmp);
  }

  
  public void setEnabled(boolean tmp) {
    this.enabled = tmp;
    checkHidden();
  }

  
  public void setEnabled(String tmp) {
    if (tmp.toLowerCase().equals("false")) {
      this.enabled = false;
    } else {
      this.enabled = true;
    }
    checkHidden();
  }

  
  public void setLastLogin(java.sql.Timestamp tmp) {
    this.lastLogin = tmp;
  }

  
  public void setLastLogin(String tmp) {
    this.lastLogin = DateUtils.parseTimestampString(tmp);
  }

  
  public void setIp(String tmp) {
    this.ip = tmp;
  }

  
  public void setTimeZone(String tmp) {
    this.timeZone = tmp;
  }

  
  public void setBuildContact(boolean tmp) {
    this.buildContact = tmp;
  }

  
  public void setBuildContactDetails(boolean tmp) {
    this.buildContactDetails = tmp;
  }

  
  public void setBuildHierarchy(boolean tmp) {
    this.buildHierarchy = tmp;
  }

  
  public void setContact(Contact tmp) {
    this.contact = tmp;
  }

  
  public void setManagerUser(User tmp) {
    this.managerUser = tmp;
  }

 
  
  public void setRoleType(int tmp) {
    this.roleType = tmp;
  }

  
  public void setRoleType(String tmp) {
    this.roleType = Integer.parseInt(tmp);
  }

  
  public java.sql.Timestamp getExpires() {
    return expires;
  }

  
  
  public java.sql.Timestamp getEntered() {
    return entered;
  }

  
  public java.sql.Timestamp getModified() {
    return modified;
  }

  

  
  public java.sql.Timestamp getLastLogin() {
    return lastLogin;
  }

  

  
  public int getAssistant() {
    return assistant;
  }

  
  public int getSiteId() {
    return siteId;
  }

  
  public String getSiteIdName() {
    return siteIdName;
  }

  
  public int getAlias() {
    return alias;
  }

  
  public int getId() {
    return id;
  }

  
  public String getUsername() {
    return username;
  }

  
  public String getPreviousUsername() {
    return previousUsername;
  }

  
  public String getPassword() {
    return password;
  }

  
  public String getEncryptedPassword() {
    if (encryptedPassword != null) {
      return encryptedPassword;
    } else {
      return this.encryptPassword(password);
    }
  }

  
  public String getPassword1() {
    return password1;
  }

  

  
  public int getContactId() {
    return contactId;
  }

  
  public int getRoleId() {
    return roleId;
  }

  
  public int getManagerId() {
    return managerId;
  }

  
  public String getRole() {
    return role;
  }

  
  public int getEnteredBy() {
    return enteredBy;
  }

  
  public String getIp() {
    return ip;
  }

  
  public String getTimeZone() {
    return timeZone;
  }

  

  
  public String getCurrency() {
    return currency;
  }

  
  public void setCurrency(String tmp) {
    this.currency = tmp;
  }

  
  public String getLanguage() {
    return language;
  }

  
  public void setLanguage(String tmp) {
    this.language = tmp;
    if (language == null) {
      locale = Locale.getDefault();
    } else {
      switch (language.length()) {
        case 2:
          locale = new Locale(language.substring(0, 2), "");
          break;
        case 5:
          locale = new Locale(language.substring(0, 2), language.substring(3, 5));
          break;
        case 10:
          // fr_FR_EURO
          locale = new Locale(language.substring(0, 2), language.substring(3, 5),
              language.substring(6));
          break;
        default:
          locale = Locale.getDefault();
          break;
      }
    }
  }

  
  public Locale getLocale() {
	  if (locale!=null){
		return locale;
	  }
    return Locale.getDefault();
  }

  
  public void setLocale(Locale tmp) {
    this.locale = tmp;
  }

 
 
  
  public int getModifiedBy() {
    return modifiedBy;
  }

  
  public boolean getEnabled() {
    return enabled;
  }

  
  public Contact getContact() {
    return contact;
  }

  
  public User getManagerUser() {
    return managerUser;
  }

  
  public int getRoleType() {
    return roleType;
  }

  
  public int getStartOfDay() {
    return startOfDay;
  }

  
  public void setStartOfDay(int startOfDay) {
    this.startOfDay = startOfDay;
  }

  
  public void setStartOfDay(String startOfDay) {
    try{
      this.startOfDay = Integer.parseInt(startOfDay);
    }catch (Exception e) {
      this.startOfDay = -1;
    }
  }

  
  public int getEndOfDay() {
    return endOfDay;
  }

  
  public void setEndOfDay(int endOfDay) {
    this.endOfDay = endOfDay;
  }

  
  public void setEndOfDay(String endOfDay) {
    try{
      this.endOfDay = Integer.parseInt(endOfDay);
    }catch (Exception e) {
      this.endOfDay = -1;
    }
  }


  @JsonIgnore  
  public boolean isPortalUser() {
    return (this.roleType > 0);
  }



  

  


  
  public void buildResources() {
    if (buildContact || buildHierarchy) {
      if (this.getContactId() > -1) {
        contact = new Contact();
        contact.setId(this.getContactId());
        contact.setBuildDetails(buildContactDetails);
        contact.setBuildTypes(buildContactDetails);
        contact.build();
      }
    }
	userPermissionList.buildList(getRoleId());
  }

  
  public void updateLogin(){
    if (this.id > -1) {
      checkHidden();
      String sql =
          "UPDATE ts_account " +
              "SET last_login = CURRENT_TIMESTAMP, " +
              "last_ip = ?, hidden = ?, " +
              "modified = CURRENT_TIMESTAMP, modifiedBy = ? " +
              "WHERE user_id = ? ";
      SQLMap pst = FrameHelper.getBaseSQL().createStatement();
      pst.setString(1, this.ip);
      pst.setBoolean(2, this.getHidden());
      pst.setInt(3, this.getModifiedBy());
      pst.setInt(4, this.id);
      pst.execute(sql);
    }
  }

  
  public void buildRecord( int userId) {

    StringBuffer sql = new StringBuffer();
    sql.append(
        "SELECT a.username, a.password, a.role_id, a.last_login, a.manager_id \n" +
            ",a.site_id AS siteid \n" +
            ",a.last_ip, a.timezone, a.startofday AS access_startofday \n" +
            ",a.endofday AS access_endofday, a.expires, a.alias \n" +
            ",a.contact_id AS contact_id_link, a.user_id AS access_user_id \n" +
            ",a.enabled AS access_enabled, a.assistant AS access_assistant \n" +
            ",a.entered AS access_entered, a.enteredby AS access_enteredby \n" +
            ",a.modified AS access_modified, a.modifiedby AS access_modifiedby \n" +
            ",a.currency, a.language, a.webdav_password, a.hidden, a.allow_webdav_access, a.allow_httpapi_access \n" +
            ",r.role AS systemrole, r.role_type \n" +
            ",m_usr.enabled AS mgr_enabled \n" +
            "FROM  ts_account a \n" +
            "LEFT JOIN ts_account m_usr ON (a.manager_id = m_usr.user_id) \n" +
            "LEFT JOIN ts_role r ON (a.role_id = r.role_id) \n" +
            "WHERE a.user_id > -1 "

			);
    if (userId > -1) {
      sql.append("AND a.user_id = :user_id ");
    } else {
      sql.append(
          "AND a.username = :username " +
              "AND a.password = :password " +
              "AND a.enabled = :enabled ");
    }
	SQLMap pst=FrameHelper.getBaseSQL().createElement();//.log(new SQLLog("buildRecord"));
//    pst = db.prepareStatement(sql.toString());
    int i = 0;
    if (userId > -1) {
      pst.setInt("user_id", userId);
    } else {
      pst.setString("username", username);
      pst.setString("password", encryptPassword(password));
      pst.setBoolean("enabled", true);
    }
	SQLList<SQLMap> elist=pst.executeQuery(sql.toString(),"");

    if (elist.size()>0) {
      buildRecord(elist.get(0));
    }
    if (id == -1) {
      throw new ISQLException("User record not found.");
    }
    buildResources();
  }



  
  public int newPassword()  {
    int resultCount = -1;

    if (this.getId() == -1) {
      throw new ISQLException("User ID was not specified");
    }
    checkHidden();
    SQLMap pst = FrameHelper.getBaseSQL().createStatement();
    StringBuffer sql = new StringBuffer();
    sql.append(
        "UPDATE ts_account " +
            "SET password = ?, hidden = ? ");
    if (modifiedBy > -1) {
      sql.append(
          ", modifiedby = ?, modified = CURRENT_TIMESTAMP ");
    }
    sql.append(" WHERE user_id = ? ");
    int i = 0;
    pst.setString(++i, encryptPassword(password1));
    pst.setBoolean(++i, this.getHidden());
    if (modifiedBy > -1) {
      pst.setInt(++i, modifiedBy);
    }
    pst.setInt(++i, getId());
    resultCount = pst.update(sql.toString());

    return resultCount;
  }

  

  
  protected void buildRecord(SQLMap rs)  {
    // account table
    this.setUsername(rs.getString("username"));
    String thisPassword = rs.getString("password");
    this.setPassword(thisPassword);
    this.setEncryptedPassword(thisPassword);
    this.setRoleId(rs.getInt("role_id"));
    lastLogin = rs.getTimestamp("last_login");
    this.setManagerId(rs.getInt("manager_id"));
    this.setSiteId(rs.getInt("siteid"));
    ip = rs.getString("last_ip");
    timeZone = rs.getString("timezone");
    startOfDay = rs.getInt("access_startofday");
    endOfDay = rs.getInt("access_endofday");
    expires = rs.getTimestamp("expires");
    this.setAlias(rs.getInt("alias"));
    this.setContactId(rs.getInt("contact_id_link"));
    this.setId(rs.getInt("access_user_id"));
    enabled = rs.getBoolean("access_enabled");
    this.setAssistant(rs.getInt("access_assistant"));
    entered = rs.getTimestamp("access_entered");
    enteredBy = rs.getInt("access_enteredby");
    modified = rs.getTimestamp("access_modified");
    modifiedBy = rs.getInt("access_modifiedby");
    currency = rs.getString("currency");
    language = rs.getString("language");
    this.setWebdavPassword(rs.getString("webdav_password"));
    hidden = rs.getBoolean("hidden");
    hasWebdavAccess = rs.getBoolean("allow_webdav_access");
    hasHttpApiAccess = rs.getBoolean("allow_httpapi_access");
    // role table
    this.setRole(rs.getString("systemrole"));
    roleType = rs.getInt("role_type");
    // user table (manager)
    if (managerId > -1) {
      managerUserEnabled = rs.getBoolean("mgr_enabled");
    } else {
      managerUserEnabled = false;
    }
    // lookup site_id table
    siteIdName = rs.getString("site_id_name");
  }



  
  private String encryptPassword(String tmp) {
    return PasswordHash.encrypt(tmp);
  }

  
  private String encryptWebdavPassword(String username, String password) {
    if (username != null && password != null) {
      return PasswordHash.encrypt(username + ":" + MVCConstant.CFS_USER_REALM
          + ":" + password);
    }
    return null;
  }

 

  
  private void checkHidden() {
    Timestamp currentTime = new Timestamp(
        Calendar.getInstance().getTimeInMillis());
    if (this.getExpires() != null && currentTime.before(this.getExpires()) && this.getEnabled()) {
      this.setHidden(false);
    } else if (this.getExpires() == null && this.getEnabled()) {
      this.setHidden(false);
    }
  }


  
  public String toString() {
    return this.getUsername() + "(" + this.getId() +","+siteId+ ")";
  }
  
  public int insertNewPassword( String newPassword) {
   	int resultCount = 0;
   	StringBuffer sql = new StringBuffer();
    SQLMap pst = FrameHelper.getBaseSQL().createStatement();
      sql.append("UPDATE ts_account SET ");
         if (newPassword != null) {
           sql.append("temp_password = ?, ");
    	   sql.append("temp_webdav_password = ?, modified = CURRENT_TIMESTAMP ");
         }
           sql.append("WHERE user_id = ? ");
           int i = 0;
    	     if (newPassword != null) {
    	       pst.setString(++i, encryptPassword(newPassword));
    	       pst.setString(++i, encryptWebdavPassword(username, newPassword));
    	     }
      pst.setInt(++i, id);
      resultCount = pst.update(sql.toString());
    return resultCount;
  } 
  
  public void overwritePassword( String password, String username, int id) {
    int resultCount = 0;
    String pw = null;
    String tempPassword = null;    
    String tempWebdavPassword = null;    
    StringBuffer sql= new StringBuffer(
            "SELECT a.temp_password, a.temp_webdav_password " +
            "FROM  ts_account a " +
            "WHERE a.username = ? ");
	SQLMap pst = FrameHelper.getBaseSQL().createStatement();
    pst.setString(1, username.toLowerCase());
    SQLList<SQLMap> elist= pst.executeQuery(sql.toString(),"");
    if (elist.size()>0) {
    	tempPassword = elist.get(0).getString("temp_password");
    	tempWebdavPassword = elist.get(0).getString("temp_webdav_password");
    }
    if (tempPassword.equals(password)){
   	 int i =0;
     sql = new StringBuffer();
     // Set password and webdav password
     sql.append("UPDATE ts_account " +
    		 	"SET " +
       		"password = ?, " +
       		"webdav_password = ?, modified = CURRENT_TIMESTAMP " +
          "WHERE user_id = ? ");
//     ps = db.prepareStatement(sql.toString());
  	 SQLMap ps = FrameHelper.getBaseSQL().createStatement();
     ps.setString(++i, tempPassword);
     ps.setString(++i, tempWebdavPassword);
     ps.setInt(++i, id);
     ps.execute(sql.toString());
     
     i = 0;
     sql = new StringBuffer();
     //reset temporary passwords
     sql.append("UPDATE ts_account " +
     			"SET " +
       		"temp_password = ?, " +
       		"temp_webdav_password = ?, modified = CURRENT_TIMESTAMP " +
       		"WHERE user_id = ? ");
//     ps = db.prepareStatement(sql.toString());
	 ps = FrameHelper.getBaseSQL().createStatement();
     ps.setString(++i, null);
     ps.setString(++i, null);
     ps.setInt(++i, id);
	 ps.execute(sql.toString());
    }
  }
	public void setUserPermissionList(UserPermissionList list){
		this.userPermissionList=list;
	}
	public UserPermissionList getUserPermissionList(){
		return this.userPermissionList;
	}  
  public boolean hasPermission( String thisPermission) {
	if ("all".equals(MVCConfig.getConfig().get("FUMINE.PERMISSION")))return true;
	if (thisPermission==null||thisPermission.equals("")){
		return true;
	}
	if (this==null||this.getId()<=0){
		return false;
	}else{
		if ("system-login".equals(thisPermission)){
			return true;
		}	
		return this.getUserPermissionList().contains(thisPermission);
	
	}

  }
  public boolean hasInPermission( String thisPermission) {
	for (String pmss:thisPermission.split(",") ){
		if (hasPermission(pmss)){
			return true;
		}
	}
	return false;
  }
  public boolean hasAllPermission( String thisPermission) {
	String[] allpmss=thisPermission.split(",");
	for (String pmss:allpmss ){
		if (!hasPermission(pmss)){
			return false;
		}
	}
	if (allpmss.length>0)return true;
	return false;
  }
}
